﻿using com.youzu.warh.protocol;
using LitJson;
using LogSystem;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Yoozoo.Framework.Core;
using Yoozoo.Gameplay.Liberty.AI;
using Yoozoo.Managers.ResourceManagerV2.Runtime;
using AnimationState = Yoozoo.Gameplay.Liberty.AI.AnimationState;

namespace Yoozoo.Gameplay.Liberty
{
    public class LibertyConfigManager : Singleton<LibertyConfigManager>
    {
        // 玩家属性配置的npcId
        public static int PLAYER_PROPERTY_NPCID = 99999;
        // 玩家连招ID映射
        public static readonly Dictionary<AnimationState, int> PLAYER_BOXING_WEAPON_IDS = new Dictionary<AnimationState, int>
        {
            { AnimationState.BoxingCombo1, 101 },   // 三段击1
            { AnimationState.BoxingCombo2, 102 },   // 三段击2
            { AnimationState.BoxingCombo3, 103 },   // 三段击3 (升龙)
            { AnimationState.BoxingAttackKick, 104 },   // 三段击3 (踢腿)
            { AnimationState.BoxingAttackDown, 105 },   // 攻击倒地单位
            { AnimationState.HandGunBoxing, 106 },   // 手枪近战
            { AnimationState.BoxingRunAttack, 107 },   // 跑动攻击
            { AnimationState.BoxingAOE, 108 },   // 近战AOE (配置从1段攻击中读取)
            { AnimationState.BoxingAOE_1, 108 },   // 近战AOE-1段伤害
            { AnimationState.BoxingAOE_2, 109 },   // 近战AOE-2段伤害
        };
        // NPC连招ID映射
        public static readonly Dictionary<AnimationState, int> NPC_BOXING_WEAPON_IDS = new Dictionary<AnimationState, int>
        {
            { AnimationState.BoxingCombo1, 201 },   // 三段击1
            { AnimationState.BoxingCombo2, 202 },   // 三段击2
            { AnimationState.BoxingCombo3, 203 },   // 三段击3 (升龙)
            { AnimationState.BoxingAttackKick, 204 },   // 三段击3 (踢腿)
            { AnimationState.BoxingAttackDown, 205 },   // 攻击倒地单位
            { AnimationState.HandGunBoxing, 206 },   // 手枪近战
        };

        // NPC模型配置
        private Dictionary<string, PbNpcDataConfig> _NpcDataConfigs;
        // NPC属性配置
        private Dictionary<int, PbAIPropertyDataConfig> _AIPropertyDataConfigs;
        // 武器属性配置
        private Dictionary<int, PbWeaponDataConfig> _WeaponDataConfigs;
        // 武器模型配置
        private Dictionary<int, PbEquipModelDataConfig> _EquipModelDataConfigs;
        // 子弹属性配置
        private Dictionary<int, PbWeaponBulletDataConfig> _WeaponBulletDataConfigs;
        // 元素属性配置
        private Dictionary<int, PbWeaponElementDataConfig> _WeaponElementDataConfigs;
        // 交互属性配置
        private Dictionary<int, Dictionary<int,PbWeaponInteractDataConfig>> _WeaponInteractDataConfigs;
        // 道具属性配置
        private Dictionary<int, PbItemConfig> _ItemConfigs;
        // 近战属性配置
        private Dictionary<int, PbBoxingDataConfig> _BoxingDataConfigs;
        private Dictionary<int, List<GTA_game_dropgroup>> _GTA_game_dropgroupConfigs;
        private ResLoader _resLoader;

        /// <summary>
        /// 初始化配置
        /// </summary>
        /// <param name="callback"></param>
        public void InitAllConfigs(Action callback)
        {
            unloadAssets();
            //_resLoader = ResLoader.Alloc();

            int loadedCount = 0;
            int totalCount = 8;
            
            // NPC模型配置
            loadProtoBufConfig<PbNpcDataConfigs>(_resLoader, "Assets/BinaryAssets/LibertyConfig/lod0_npc.bytes", configs =>
            {
                if (configs == null)
                {
                    _NpcDataConfigs = new Dictionary<string, PbNpcDataConfig>();
                }
                else
                {
                    _NpcDataConfigs = new Dictionary<string, PbNpcDataConfig>(configs.Data.Count);
                    foreach (var dataItem in configs.Data)
                    {
                        _NpcDataConfigs.Add(dataItem.Point_Name, dataItem);
                    }
                }

                ++loadedCount;
                if (loadedCount >= totalCount)
                {
                    unloadAssets();
                    callback?.Invoke();
                }
            });
            // 角色属性配置
            loadProtoBufConfig<PbAIPropertyDataConfigs>(_resLoader, "Assets/BinaryAssets/LibertyConfig/rpg_npc.bytes", configs =>
            {
                if (configs == null)
                {
                    _AIPropertyDataConfigs = new Dictionary<int, PbAIPropertyDataConfig>();
                }
                else
                {
                    _AIPropertyDataConfigs = new Dictionary<int, PbAIPropertyDataConfig>(configs.Data.Count);
                    foreach (var dataItem in configs.Data)
                    {
                        _AIPropertyDataConfigs.Add(dataItem.id, dataItem);
                    }
                }

                ++loadedCount;
                if (loadedCount >= totalCount)
                {
                    unloadAssets();
                    callback?.Invoke();
                }
            });
            // 武器数据配置
            loadProtoBufConfig<PbWeaponDataConfigs>(_resLoader, "Assets/BinaryAssets/LibertyConfig/GTA_weapon.bytes", configs =>
            {
                if (configs == null)
                {
                    _WeaponDataConfigs = new Dictionary<int, PbWeaponDataConfig>();
                }
                else
                {
                    _WeaponDataConfigs = new Dictionary<int, PbWeaponDataConfig>(configs.Data.Count);
                    foreach (var dataItem in configs.Data)
                    {
                        _WeaponDataConfigs.Add(dataItem.weapon_id, dataItem);
                    }
                }
                
                ++loadedCount;
                if (loadedCount >= totalCount)
                {
                    unloadAssets();
                    callback?.Invoke();
                }
            });
            // 武器模型数据配置
            loadProtoBufConfig<PbEquipModelDataConfigs>(_resLoader, "Assets/BinaryAssets/LibertyConfig/GTA_equip_model.bytes", configs =>
            {
                if (configs == null)
                {
                    _EquipModelDataConfigs = new Dictionary<int, PbEquipModelDataConfig>();
                }
                else
                {
                    _EquipModelDataConfigs = new Dictionary<int, PbEquipModelDataConfig>(configs.Data.Count);
                    foreach (var dataItem in configs.Data)
                    {
                        _EquipModelDataConfigs.Add(dataItem.weapon_id, dataItem);
                    }
                }
                
                ++loadedCount;
                if (loadedCount >= totalCount)
                {
                    unloadAssets();
                    callback?.Invoke();
                }
            });
            // 武器数据配置
            loadProtoBufConfig<PbWeaponBulletDataConfigs>(_resLoader, "Assets/BinaryAssets/LibertyConfig/GTA_weapon_bullet.bytes", configs =>
            {
                if (configs == null)
                {
                    _WeaponBulletDataConfigs = new Dictionary<int, PbWeaponBulletDataConfig>();
                }
                else
                {
                    _WeaponBulletDataConfigs = new Dictionary<int, PbWeaponBulletDataConfig>(configs.Data.Count);
                    foreach (var dataItem in configs.Data)
                    {
                        _WeaponBulletDataConfigs.Add(dataItem.bullet_id, dataItem);
                    }
                }
                
                ++loadedCount;
                if (loadedCount >= totalCount)
                {
                    unloadAssets();
                    callback?.Invoke();
                }
            });
            // 元素数据配置
            loadProtoBufConfig<PbWeaponElementDataConfigs>(_resLoader, "Assets/BinaryAssets/LibertyConfig/GTA_weapon_element.bytes", configs =>
            {
                if (configs == null)
                {
                    _WeaponElementDataConfigs = new Dictionary<int, PbWeaponElementDataConfig>();
                }
                else
                {
                    _WeaponElementDataConfigs = new Dictionary<int, PbWeaponElementDataConfig>(configs.Data.Count);
                    foreach (var dataItem in configs.Data)
                    {
                        _WeaponElementDataConfigs.Add(dataItem.element_id, dataItem);
                    }
                }
                
                ++loadedCount;
                if (loadedCount >= totalCount)
                {
                    unloadAssets();
                    callback?.Invoke();
                }
            });
            // 交互数据配置
            loadProtoBufConfig<PbWeaponInteractDataConfigs>(_resLoader, "Assets/BinaryAssets/LibertyConfig/GTA_weapon_interact.bytes", configs =>
            {
                if (configs == null)
                {
                    _WeaponInteractDataConfigs = new Dictionary<int, Dictionary<int, PbWeaponInteractDataConfig>>();
                }
                else
                {
                    _WeaponInteractDataConfigs = new Dictionary<int, Dictionary<int, PbWeaponInteractDataConfig>>();
                    foreach (var dataItem in configs.Data)
                    {
                        if (!_WeaponInteractDataConfigs.TryGetValue(dataItem.interact_type,out var firstDic))
                        {
                            firstDic = new Dictionary<int, PbWeaponInteractDataConfig>();
                            _WeaponInteractDataConfigs.Add(dataItem.interact_type,firstDic);
                        }

                        if (!firstDic.TryGetValue(dataItem.object_type,out var secondDic ))
                        {
                            firstDic.Add(dataItem.object_type, dataItem);
                        }
                    }
                }
                
                ++loadedCount;
                if (loadedCount >= totalCount)
                {
                    unloadAssets();
                    callback?.Invoke();
                }
            });
            // 道具数据配置
            loadProtoBufConfig<PbItemConfigs>(_resLoader, "Assets/BinaryAssets/LibertyConfig/GTA_item.bytes", configs =>
            {
                if (configs == null)
                {
                    _ItemConfigs = new Dictionary<int, PbItemConfig>();
                }
                else
                {
                    _ItemConfigs = new Dictionary<int, PbItemConfig>(configs.Data.Count);
                    foreach (var dataItem in configs.Data)
                    {
                        _ItemConfigs.Add(dataItem.id, dataItem);
                    }
                }
                
                ++loadedCount;
                if (loadedCount >= totalCount)
                {
                    unloadAssets();
                    callback?.Invoke();
                }
            });
            // 近战数据配置
            loadProtoBufConfig<PbBoxingDataConfigs>(_resLoader, "Assets/BinaryAssets/LibertyConfig/GTA_skill.bytes", configs =>
            {
                if (configs == null)
                {
                    _BoxingDataConfigs = new Dictionary<int, PbBoxingDataConfig>();
                }
                else
                {
                    _BoxingDataConfigs = new Dictionary<int, PbBoxingDataConfig>(configs.Data.Count);
                    foreach (var dataItem in configs.Data)
                    {
                        _BoxingDataConfigs.Add(dataItem.weapon_id, dataItem);
                    }
                }

                ++loadedCount;
                if (loadedCount >= totalCount)
                {
                    unloadAssets();
                    callback?.Invoke();
                }
            });
            
            //_resLoader.Load();
        }

        /// <summary>
        /// 设置物理碰撞矩阵
        /// </summary>
        public void SetPhysicsLayerCollisionMatrix(string jsonPath, Action callback)
        {
            ResLoader resLoader = ResLoader.Alloc();
            
            resLoader.Add2Load(jsonPath, (success, name, asset) => {
                if (success)
                {
                    var json = asset as TextAsset;
                    if (json)
                    {
                        if (!string.IsNullOrEmpty(json.text))
                        {
                            var layerCollisionMatrix = JsonMapper.ToObject<bool[][]>(json.text);

                            int MaxLayer = layerCollisionMatrix.Length - 1;
                            int layer1, layer2;
                            for (int i = 0; i < layerCollisionMatrix.Length; i++)
                            {
                                layer1 = i;
                                for (int j = 0; j < layerCollisionMatrix[layer1].Length; j++)
                                {
                                    layer2 = MaxLayer - j;
// #if UNITY_EDITOR
//                                     if (!layerCollisionMatrix[i][j])
//                                     {
//                                         Debug.LogError($"LayerCollision: ({layer1}, {layer2}) = {layerCollisionMatrix[i][j]}");
//                                     }
// #endif
                                    Physics.IgnoreLayerCollision(layer1, layer2, !layerCollisionMatrix[i][j]);
                                }
                            }
                        }
                    }
                    
                    callback?.Invoke();
                }
                else
                {
                    Debug.LogError("load Asset failed : {0} " + name);
                }
                
                resLoader.Recycle2Cache();
            });
            resLoader.Load();
        }
        
        /// <summary>
        /// 获取npc模型配置
        /// </summary>
        /// <param name="pointName"></param>
        /// <returns></returns>
        public PbNpcDataConfig GetNpcDataConfig(string pointName)
        {
            PbNpcDataConfig npcDataConfig = null;
            if (_NpcDataConfigs.TryGetValue(pointName, out npcDataConfig))
            {
                return npcDataConfig;
            }
            Debug.LogWarning(LogModule.LibertySceneBattle,$"获取npc模型配置失败 pointName: {pointName}");
            return null;
        }

        /// <summary>
        /// 获取角色属性配置
        /// </summary>
        /// <param name="npcId"></param>
        /// <returns></returns>
        public PbAIPropertyDataConfig GetAIPropertyDataConfig(int npcId)
        {
            PbAIPropertyDataConfig aiPropertyData = null;
            if (_AIPropertyDataConfigs.TryGetValue(npcId, out aiPropertyData))
            {
                return aiPropertyData;
            }
            Debug.LogError(LogModule.LibertySceneBattle,$"获取npc属性配置失败 npcId: {npcId}");
            return null;
        }

        /// <summary>
        /// 获取近战属性配置
        /// </summary>
        /// <param name="weaponId"></param>
        /// <returns></returns>
        public PbBoxingDataConfig GetBoxingDataConfig(int uniqueId, AnimationState animationState)
        {
            Dictionary<AnimationState, int> weaponIdMap;
            if (uniqueId == LibertyAIUtils.PLAYER_AI_ID)
            {
                weaponIdMap = PLAYER_BOXING_WEAPON_IDS;
            }
            else
            {
                weaponIdMap = NPC_BOXING_WEAPON_IDS;
            }
            int weaponId;
            if (weaponIdMap.TryGetValue(animationState, out weaponId))
            {
                PbBoxingDataConfig boxingData = null;
                if (_BoxingDataConfigs.TryGetValue(weaponId, out boxingData))
                {
                    return boxingData;
                }
            }
            Debug.LogError(LogModule.LibertySceneBattle,$"获取近战配置失败 animationState: {animationState.ToString()}, weaponId: {weaponId}");
            return null;
        }
        
        /// <summary>
        /// 获取武器属性配置
        /// </summary>
        /// <param name="weaponId"></param>
        /// <returns></returns>
        public PbWeaponDataConfig GetWeaponDataConfig(int weaponId)
        {
            PbWeaponDataConfig weaponData = null;
            if (_WeaponDataConfigs.TryGetValue(weaponId, out weaponData))
            {
                return weaponData;
            }
            if (weaponId > 0)
            {
                Debug.LogError(LogModule.LibertySceneBattle,$"获取武器配置失败 weaponId: {weaponId}");
            }
            return null;
        }

        /// <summary>
        /// 获取武器模型配置
        /// </summary>
        /// <param name="weaponId"></param>
        /// <returns></returns>
        public PbEquipModelDataConfig GetEquipModelDataConfig(int weaponId)
        {
            PbEquipModelDataConfig equipModelData = null;
            if (_EquipModelDataConfigs.TryGetValue(weaponId, out equipModelData))
            {
                return equipModelData;
            }
            if (weaponId > 0)
            {
                Debug.LogError(LogModule.LibertySceneBattle,$"获取武器模型配置失败 weaponId: {weaponId}");
            }
            return null;
        }
        
        /// <summary>
        /// 获取子弹属性配置
        /// </summary>
        /// <param name="bulletId"></param>
        /// <returns></returns>
        public PbWeaponBulletDataConfig GetWeaponBulletDataConfig(int bulletId)
        {
            PbWeaponBulletDataConfig bulletData = null;
            if (_WeaponBulletDataConfigs.TryGetValue(bulletId, out bulletData))
            {
                return bulletData;
            }
            if (bulletId > 0)
            {
                Debug.LogError(LogModule.LibertySceneBattle,$"获取子弹配置失败 bulletId: {bulletId}");
            }
            return null;
        }
        
        /// <summary>
        /// 获取元素属性配置
        /// </summary>
        /// <param name="elementId"></param>
        /// <returns></returns>
        public PbWeaponElementDataConfig GetWeaponElementDataConfig(int elementId)
        {
            PbWeaponElementDataConfig elementData = null;
            if (_WeaponElementDataConfigs.TryGetValue(elementId, out elementData))
            {
                return elementData;
            }
            if (elementId > 0)
            {
                Debug.LogError(LogModule.LibertySceneBattle,$"获取元素配置失败 elementId: {elementId}");
            }
            return null;
        }

        /// <summary>
        /// 获取交互属性配置
        /// </summary>
        /// <param name="interacType"></param>
        /// <returns></returns>
        public PbWeaponInteractDataConfig GetWeaponInteractDataConfig(int interacType, int objectType)
        {
            Dictionary<int, PbWeaponInteractDataConfig> dictionarys = null;
            PbWeaponInteractDataConfig elementData = null;
            if (_WeaponInteractDataConfigs.TryGetValue(interacType, out dictionarys))
            {
                if (dictionarys.TryGetValue(objectType,out elementData))
                {
                    return elementData;
                }
            }
            if (interacType > 0)
            {
                Debug.LogError(LogModule.LibertySceneBattle, $"获取交互配置失败 interacType: {interacType}  objectType: {objectType}");
            }

            return null;
        }
        
        /// <summary>
        /// 获取道具属性配置
        /// </summary>
        /// <param name="elementId"></param>
        /// <returns></returns>
        public PbItemConfig GetItemDataConfig(int id)
        {
            PbItemConfig itemData = null;
            if (_ItemConfigs.TryGetValue(id, out itemData))
            {
                return itemData;
            }
            if (id > 0)
            {
                Debug.LogError(LogModule.LibertySceneBattle,$"获取道具配置失败 elementId: {id}");
            }
            return null;
        }
        
        public void LoadGameDropGroupConfig(Action callback)
        {
            if (_resLoader == null)
            {
                _resLoader = ResLoader.Alloc();
            }
            // 近战数据配置
            loadJsonConfig<List<GTA_game_dropgroup>>(_resLoader,
                "Assets/ResourcesAssets/Config/LibertyConfig/GTA_game_dropgroup.json", configs =>
                {
                    if (_GTA_game_dropgroupConfigs == null)
                    {
                        _GTA_game_dropgroupConfigs = new Dictionary<int, List<GTA_game_dropgroup>>();
                    }

                    foreach (var dataItem in configs)
                    {
                        if (!_GTA_game_dropgroupConfigs.TryGetValue(dataItem.id, out var gtaDroupConfigList))
                        {
                            gtaDroupConfigList = new List<GTA_game_dropgroup>();
                            _GTA_game_dropgroupConfigs.Add(dataItem.id, gtaDroupConfigList);
                        }

                        gtaDroupConfigList.Add(dataItem);
                    }

                    callback?.Invoke();
                });
            _resLoader.Load();
        }
        /// <summary>
        /// 获取道具掉落包
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public List<GTA_game_dropgroup> GetGTA_game_dropgroupConfigs(int id)
        {
            List<GTA_game_dropgroup> groupList = null;
            if (_GTA_game_dropgroupConfigs.TryGetValue(id, out groupList))
            {
                return groupList;
            }
            return null;
        }

        void loadProtoBufConfig<T>(ResLoader resLoader, string path, Action<T> callback) where T : class
        {
            var fileSystemBuffer = UMTResource.Buffer;
            if (UMTResource.LoadBinaryFromFileSystem(path, fileSystemBuffer))
            {
                using (MemoryStream memoryStream = new MemoryStream(fileSystemBuffer.Bytes,0, fileSystemBuffer.Length))
                {
                    try
                    {
                        var configs = ProtoBuf.Serializer.Deserialize<T>(memoryStream);
                        callback?.Invoke(configs);
                    }
                    catch (Exception e)
                    {
                        Debug.LogException(e);
                        callback?.Invoke(null);
                    }
                }
            }
            else
            {
                Debug.LogErrorFormat(LogModule.LibertyScene, "loadProtoBufConfig failed : {0} ", path);
            }
        }
    
        void loadJsonConfig<T>(ResLoader resLoader, string path, Action<T> callback) where T : class
        {
            resLoader.Add2Load(path, (success, name, asset) => {
                if (success)
                {
                    var json = asset as TextAsset;
                    if (json)
                    {
                        if (!string.IsNullOrEmpty(json.text))
                        {
                            var datas = JsonMapper.ToObject<T>(json.text);
                            callback?.Invoke(datas);
                        }
                    }
                }
                else
                {
                    Debug.LogError("load Asset failed : {0} " + name);
                }
            });
            
        }
        
        void unloadAssets()
        {
            if (_resLoader != null)
            {
                _resLoader.Recycle2Cache();
                _resLoader = null;
            }
        }
        
    }
}
